package monitor

import (
	"encoding/json"
	"errors"
	apis2 "gluenet/pkg/apis"
	"gluenet/pkg/log/v1"
	"gluenet/pkg/nets"
	"gluenet/utils/rpc/labels"
)

const (
	switchOn  = "on"
	switchOff = "off"

	monitorLog    = "log"
	monitorMetric = "metric"
	monitorTrace  = "trace"
)

type SRequest struct {
	Switch  string   `json:"switch" yaml:"switch"`
	Monitor string   `json:"monitor" yaml:"monitor"`
	Guid    []string `json:"guid" yaml:"guid"`
}

type JRequest struct {
	Guid  string `json:"guid" yaml:"guid"`
	Topic string `json:"topic" yaml:"topic"`
}

type JResponse struct {
	Code    int         `json:"code" yaml:"code"`
	Message string      `json:"message" yaml:"message"`
	Data    interface{} `json:"data" yaml:"data"`
}

func Switch(c *apis2.GlueContext) {
	req := SRequest{}
	if err := c.WebContext.ReadJSON(&req); err != nil {
		n, _ := c.WebContext.JSON(apis2.ResponseReqErr(err, req))
		c.Logger.Debugf("request response byte:%v read data: %v", n, err)
		return
	}

	switch req.Monitor {
	case monitorTrace:
		c.Logger.Debugf("monitor trace")
		for _, guid := range req.Guid {
			if R, err := requestTrace(c.Logger, c.Rpc, guid, req.Switch, apis2.TracePush); err != nil {
				n, _ := c.WebContext.JSON(apis2.ResponseReqErr(err, R))
				c.Logger.Debugf("request response byte:%v read data: %v", n, err)
				return
			}
		}
	case monitorLog:
		c.Logger.Debugf("monitor log")
		for _, guid := range req.Guid {
			if R, err := requestLog(c.Logger, c.Rpc, guid, req.Switch, apis2.LogPush); err != nil {
				n, _ := c.WebContext.JSON(apis2.ResponseReqErr(err, R))
				c.Logger.Debugf("request response byte:%v read data: %v", n, err)
				return
			}
		}
	case monitorMetric:
		c.Logger.Debugf("monitor metric")
		for _, guid := range req.Guid {
			if R, err := requestMetrics(c.Logger, c.Rpc, guid, req.Switch, apis2.MetricsPush); err != nil {
				n, _ := c.WebContext.JSON(apis2.ResponseReqErr(err, R))
				c.Logger.Debugf("request response byte:%v read data: %v", n, err)
				return
			}
		}
	default:
		c.Logger.Errorf("unknown type")
		return
	}

	apis2.ResponseOK(nil)
	n, err := c.WebContext.JSON(apis2.ResponseOK(nil))
	c.Logger.Debugf("request response byte:%v write response %v", n, err)
}

func requestTrace(logger v1.Logger, c nets.GlueNets, guid, sw, topic string) ([]byte, error) {
	// manager's guid and push topic
	req := JRequest{
		Guid:  labels.ControlManager,
		Topic: topic,
	}

	bts, err := json.Marshal(req)
	if err != nil {
		return nil, err
	}

	switch sw {
	case switchOn:
		return c.Request(guid+":"+apis2.RPCTraceSwitchOn, bts)
	case switchOff:
		return c.Request(guid+":"+apis2.RPCTraceSwitchOff, bts)
	default:
		return nil, errors.New("unknown switch state")
	}
}

func requestMetrics(logger v1.Logger, c nets.GlueNets, guid, sw, topic string) ([]byte, error) {
	// manager's guid and push topic
	req := JRequest{
		Guid:  labels.ControlManager,
		Topic: topic,
	}

	bts, err := json.Marshal(req)
	if err != nil {
		return nil, err
	}

	logger.Debugf("metrics push switch data [%s]", bts)
	logger.Debugf("metrics req [%v:%v]", guid, apis2.RPCMetriceSwitchOn)
	logger.Debugf("metrics req [%v:%v]", guid, apis2.RPCMetriceSwitchOff)

	switch sw {
	case switchOn:
		return c.Request(guid+":"+apis2.RPCMetriceSwitchOn, bts)
	case switchOff:
		return c.Request(guid+":"+apis2.RPCMetriceSwitchOff, bts)
	default:
		return nil, errors.New("unknown switch state")
	}
}

func requestLog(logger v1.Logger, c nets.GlueNets, guid, sw, topic string) ([]byte, error) {
	// manager's guid and push topic
	req := JRequest{
		Guid:  labels.ControlManager,
		Topic: topic,
	}

	bts, err := json.Marshal(req)
	if err != nil {
		return nil, err
	}

	switch sw {
	case switchOn:
		return c.Request(guid+":"+apis2.RPCLogSwitchOn, bts)
	case switchOff:
		return c.Request(guid+":"+apis2.RPCLogSwitchOff, bts)
	default:
		return nil, errors.New("unknown switch state")
	}
}
